package com.huiyeji.dynamic.core.parser;

import com.huiyeji.dynamic.core.DynamicContext;
import com.huiyeji.dynamic.core.DynamicRegex;
import com.huiyeji.dynamic.core.DynamicStatement;
import com.huiyeji.dynamic.core.RegexContainer;
import com.huiyeji.dynamic.core.builder.ParamProviderBuilder;
import com.huiyeji.dynamic.core.exception.DynamicStatementParseException;
import com.huiyeji.dynamic.core.handler.DynamicBuilderPrefixHandler;
import com.huiyeji.dynamic.core.handler.PrefixHandler;
import com.huiyeji.dynamic.core.handler.ReturnPrefixHandler;
import com.huiyeji.dynamic.core.provider.ParamProvider;
import com.huiyeji.dynamic.core.provider.StatementParamProvider;
import com.huiyeji.sort.ObjectMatcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Huiyeji
 */
public class DefaultDynamicStatementParser implements DynamicParser{

    public static final String DEFAULT_PARSER_REGEX =
            ".*" +
            DynamicRegex.OBJECT_NAME.origin() + DynamicRegex.DECIMAL_POINT.origin() + DynamicRegex.METHOD.origin() +
            ".*";

    @Override
    public DynamicStatement parse(DynamicContext context, String originStatement) {
        boolean requireExecute = true;
        String dynamicObjectName = null;
        String dynamicPrefix = null;
        String dynamicMethodName = null;
        String dynamicResultName = null;
        PrefixHandler prefixHandler = null;
        List<ParamProvider> paramProviders = null;

        if (originStatement == null){
            requireExecute = false;
        } else {

            String statement = originStatement.trim();
            if ("".equals(statement) || statement.startsWith("//")){
                requireExecute = false;
            } else {
                String[] statementArray = statement.split("\\.",2);
                if (statementArray.length != 2){
                    throw new DynamicStatementParseException(originStatement);
                }
                String statementPrefix = statementArray[0];
                String statementSuffix = statementArray[1];

                if ("".equals(statementPrefix.trim())){
                    throw new DynamicStatementParseException(originStatement);
                }

                String[] dynamicObjectNameArray = statementPrefix.split("=");
                if (dynamicObjectNameArray.length > 2){
                    throw new DynamicStatementParseException(originStatement);
                }

                if (dynamicObjectNameArray.length == 1){
                    dynamicObjectName = dynamicObjectNameArray[0].trim();
                }

                if (dynamicObjectNameArray.length == 2){
                    dynamicObjectName = dynamicObjectNameArray[1].trim();
                    String[] prefixArray = dynamicObjectNameArray[0].trim().split(" ");
                    if (prefixArray.length > 2){
                        throw new DynamicStatementParseException(originStatement);
                    }

                    if (prefixArray.length == 2){
                        dynamicPrefix = prefixArray[0].trim();
                        dynamicResultName = prefixArray[1].trim();
                        if (!"".equals(dynamicPrefix) && !"".equals(dynamicResultName)){
                            if (dynamicPrefix.equals("return")){
                                prefixHandler = new ReturnPrefixHandler(dynamicResultName);
                            } else {
                                prefixHandler = new DynamicBuilderPrefixHandler(dynamicPrefix,dynamicResultName);
                            }
                        }
                    }

                    if (prefixArray.length == 1){
                        dynamicResultName = prefixArray[0].trim();
                    }
                }

                String[] suffixArray = statementSuffix.split("\\(",2);

                if (suffixArray.length != 2){
                    throw new DynamicStatementParseException(originStatement);
                }

                dynamicMethodName = suffixArray[0].trim();

                String paramsProviderArrayStatement = suffixArray[1].trim();

                if (!paramsProviderArrayStatement.endsWith(")")){
                    throw new DynamicStatementParseException(originStatement);
                }

                paramsProviderArrayStatement = paramsProviderArrayStatement.substring(0, paramsProviderArrayStatement.length() - 1);

                paramProviders = parseParamProviders(context,paramsProviderArrayStatement);
            }
        }

        return new DynamicStatement(originStatement, requireExecute, dynamicResultName, dynamicPrefix, dynamicObjectName, dynamicMethodName, prefixHandler, paramProviders);
    }

    private List<ParamProvider> parseParamProviders(DynamicContext context,String paramsProviderStatement){
        List<ParamProvider> paramProviders = new ArrayList<ParamProvider>();
        String statement = paramsProviderStatement.trim();
        if (statement.equals("")){
            return paramProviders;
        }

        int previousIndex = 0;

        ObjectMatcher<String, RegexContainer, ParamProviderBuilder> matcher = context.getParamProviderBuilderMatcher();

        ParamProviderBuilder fBuilder = matcher.matchObject(statement);
        if (fBuilder != null){
            ParamProvider fProvider = fBuilder.build(statement);
            paramProviders.add(fProvider);
            if (fProvider instanceof StatementParamProvider){
                StatementParamProvider statementParamProvider = (StatementParamProvider) fProvider;
                statementParamProvider.parseWrapper(context);
            }
            return paramProviders;
        }

        for (int i = 0; i < statement.length(); i++) {
            if (statement.charAt(i) == ','){
                String paramStatement = statement.substring(previousIndex,i).trim();

                ParamProviderBuilder paramProviderBuilder = matcher.matchObject(paramStatement);

                if (paramProviderBuilder != null){
                    previousIndex = i + 1;
                    ParamProvider paramProvider = paramProviderBuilder.build(paramStatement);
                    paramProviders.add(paramProvider);
                    if (paramProvider instanceof StatementParamProvider){
                        StatementParamProvider statementParamProvider = (StatementParamProvider) paramProvider;
                        statementParamProvider.parseWrapper(context);
                    }
                }
            }
        }

        String lastParamStatement = statement.substring(previousIndex).trim();

        ParamProviderBuilder paramProviderBuilder = matcher.matchObject(lastParamStatement);
        if (paramProviderBuilder == null){
            throw new DynamicStatementParseException("the last param 【"+lastParamStatement+"】 parse error !");
        }
        ParamProvider paramProvider = paramProviderBuilder.build(lastParamStatement);
        paramProviders.add(paramProvider);

        if (paramProvider instanceof StatementParamProvider){
            StatementParamProvider statementParamProvider = (StatementParamProvider) paramProvider;
            statementParamProvider.parseWrapper(context);
        }

        return paramProviders;
    }

    @Override
    public RegexContainer ruleInitialize() {
        return new RegexContainer(Arrays.asList(
                DEFAULT_PARSER_REGEX,
                "(\\s*//.*|\\s*)"
        ));
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
